%%%-------------------------------------------------------------------
%%% @author liuwentao
%%% @doc
%%%     背包
%%% @end
%%% Created : 19. 7月 2021 14:47
%%%-------------------------------------------------------------------
-module(package).
-author("liuwentao").

-export([
    init/1                          %% 背包初始化
    , type_to_package/2             %% 根据类型获取背包
    , update_role_package/3         %% 更新角色背包
    , add/4                         %% 给背包增加道具
    , add/5                         %% 给背包增加道具
    , combine/2                     %% @todo 合并道具
    , merge/1                       %% 合并道具
    , sort/2                        %% 排序
    , merge_bind/1                  %% 合并绑定物品
    , del/3                         %% 删除道具
    , find/3                        %% 查找道具
    , count/3                       %% 统计道具
    , count_bind/4                  %% 统计绑定道具
    , find_bind_unbind/2            %% 获取非绑定道具
    , fetch/3                       %% 查找道具
    , fresh_item/4                  %% 替换道具
    , replace_item/4                %% 更新道具
    , push_item_info/3              %% 单物品推送通知
    , split_item/4                  %% 切分背包
    , push_gain/2                   %% 损益推送通知
    , find_num/3                    %% 获取背包道具数量
    , find_group/3                  %% 根据物品组获取道具数量
    , find_bind_num/4               %% 根据物品bid 查取数量
    , free_cell_num/2               %% 获取空格子数量
    , items_change_bind/3
    , ato_sort/1                    %% 自动排序
]).

-include("package.hrl").
-include("item.hrl").
-include("role.hrl").
-include("trigger.hrl").
-include("conn.hrl").
-include("common.hrl").

%% @doc 初始化背包
-spec init(Atom) -> #package{} when
    Atom :: bag | store.
init(bag) ->
    #package{type = ?package_type_bag, volume = ?package_bag_size, free_cell = ?free_cell(1, ?package_bag_size)};
init(store) ->
    #package{type = ?package_type_store, volume = ?package_store_size, free_cell = ?free_cell(1, ?package_store_size)}.

%% @doc 根据类型获取背包
type_to_package(?package_type_bag, #role{p_bag = Bag}) -> Bag;
type_to_package(?package_type_store, #role{p_store = Bag}) -> Bag;
type_to_package(_, #role{}) -> false.

%% @doc 根据类型保存背包
update_role_package(?package_type_bag, NewBag, Role) ->
    Role#role{p_bag = NewBag};
update_role_package(?package_type_store, NewBag, Role) ->
    Role#role{p_store = NewBag};
update_role_package(Type, _, Role) ->
    ?ERR("未知的背包类型~w", [Type]),
    Role.

%% @doc 增加物品, 带刷新通知
%% 注意！在上层普通模块不要调用这个接口！需要通过role_gain:do/do_notice来增加！！
%% <div>注意当Flag为eqm仅可使用by_items,而且ID和POS已经设置好</div>
add(by_items, Flag, Role, ItemInfo) ->
    add_items(Flag, Role, ItemInfo);
add(by_base_id, Flag, Role, ItemInfo) ->
    add_base_id(Flag, Role, ItemInfo).

%% @doc 增加物品，不带刷新通知,需手动收集之后再调用push_item_info
%% 注意！在上层普通模块不要调用这个接口！需要通过role_gain:do/do_notice来增加！！
add(by_items, Flag, Role, ItemInfo, no_push) ->
    add_no_push_items(Flag, Role, ItemInfo);
add(by_base_id, Flag, Role, ItemInfo, no_push) ->
    add_no_push_base_id(Flag, Role, ItemInfo).


%% @doc 直接增加物品列表
add_items(Type, Role = #role{}, Items) ->
    %% 获取具体的背包
    Bag = type_to_package(Type, Role),
    add_package(Bag, Role, Items).

%% @doc 增加BaseId物品列表
add_base_id(Flag, Role, ItemInfo) ->
    add_base_id(Flag, Role, ItemInfo, []).
add_base_id(Flag, Role, [], Items) ->
    add_items(Flag, Role, Items);
add_base_id(Flag, Role, [{BaseId, Bind, Num} | T], Items) ->
    %% 构造道具
    case item:make(BaseId, Bind, Num) of
        false -> false;
        {ok, NewItems} ->
            add_base_id(Flag, Role, T, NewItems ++ Items)
    end;
add_base_id(Flag, Role, [H = #{base_id := _BaseId, bind := _Bind, quantity := _Num} | T], Items) ->
    case item:make(H) of
        false -> false;
        {ok, NewItems} ->
            add_base_id(Flag, Role, T, NewItems ++ Items)
    end;
add_base_id(_Flag, _Role, [_H | _T], _Items) ->
    ?DEBUG("物品配置  ~w", [_H]),
    false.

%% @doc 增加道具到背包，并且推送消息
add_package(Package, Role, Items) ->
    add_package(Package, Role, Items, #{new => [], add => [], update => []}).
add_package(Package = #package{type = Type}, Role, [], #{add := Add, update := Update}) ->
    %% 推送背包增加
    push_item_info(add, Role, [{Type, Add}]),
    %% 推送道具信息更新
    push_item_info(update, Role, [{Type, Update}]),
    {ok, Package};
add_package(Package, Role, [H | T], BackItems) ->
    %% 实际增加背包
    case do_add(Package, H, Role, BackItems) of
        false -> false;
        full -> full;
        {ok, NewPackage, NewBackItems} ->
            add_package(NewPackage, Role, T, NewBackItems)
    end.

%% @doc 增加物品
do_add(#package{free_cell = []}, _Item, _Role, _BackItems) -> full;
do_add(Package = #package{next_id = NextId, free_cell = [Pos | FreeCell], items = Items}, Item = #item{base_id = BaseId, expire_time = ItemExpireTime}, #role{}, BackItems = #{new := New, add := Add}) ->
    Now = date:unixtime(),
    if
        ItemExpireTime > Now orelse ItemExpireTime =:= 0 -> %% 不是过期的物品
            NewItem = Item#item{id = NextId, pos = Pos},
            case item_data:get(BaseId) of
                #item_base{overlap = 1} ->
                    {ok, Package#package{next_id = NextId + 1, free_cell = FreeCell, items = [NewItem | Items]}, BackItems#{new => [NewItem | New], add => [NewItem | Add]}};
                #item_base{overlap = OverLap} ->
                    %% 合并道具
                    case merge_item(NewItem, Items, OverLap, BackItems) of
                        {ok, NewItems, NewBackItems} ->
                            NewPackAge = Package#package{next_id = NextId, free_cell = [Pos | FreeCell], items = NewItems},
                            {ok, NewPackAge, NewBackItems};
                        _ ->
                            {ok, Package#package{next_id = NextId + 1, free_cell = FreeCell, items = [NewItem | Items]}, BackItems#{new => [NewItem | New], add => [NewItem | Add]}}
                    end
            end;
        true ->
            {ok, Package, BackItems}
    end.


%% @doc 整理背包
-spec sort(Mode, #role{}) -> {ok, #package{}} when
    Mode :: bag | store.
sort(bag, Role = #role{p_bag = Bag = #package{volume = Volume, type = ?package_type_bag, items = BagItems}, link = #link{conn_pid = ConnPid}}) ->
    %% 检查过期道具
    {Items, ExpireItems} = check_expire(BagItems, [], []),
    DelItems = [{?package_type_bag, I} || I <- ExpireItems],
    server_conn:pack_send(ConnPid, 10311, {DelItems}),
    %% 背包道具排序
    SortItem = lists:sort(fun sort_type/2, combine(lists:sort(Items), [])),
    %% 设置道具编号
    {NewFreeCell, NewItems} = add_new_pos(SortItem, ?free_cell(1, Volume)),
    %% 推送物品增加和删除
    check_sort_result(Role, ?package_type_bag, Items, NewItems),
    ItemList = lists:reverse(NewItems),
    {ok, Bag#package{free_cell = NewFreeCell, items = ItemList}}.


%% @doc 处理过期道具
check_expire([], Items, ExpireItems) -> {Items, ExpireItems};
check_expire([I = #item{expire_time = ExpireTime} | T], Items, ExpireItems) ->
    Now = date:unixtime(),
    if
        Now >= ExpireTime andalso ExpireTime =/= 0 ->
            check_expire(T, Items, [I | ExpireItems]);
        true ->
            check_expire(T, [I | Items], ExpireItems)
    end.


%% @doc 删除包裹里面的物品
%% <div>删除身上装备仅产生Dellist, 不会产生Freshlist</div>
-spec del(Flag, #package{}, ItemInfo, ExpireFlag) -> {false, bitstring()} | {ok, #package{}, DelList, FreshList} | {ok, #package{}, DelList} when
    Flag :: by_id | by_base_id,
    ItemInfo :: [{ItemId, non_neg_integer()}] | [{ItemBaseId, non_neg_integer()}]| [{ItemBaseId, non_neg_integer(), non_neg_integer()}],
    ItemId :: non_neg_integer(),
    ItemBaseId :: non_neg_integer(),
    DelList :: [#item{}],
    FreshList :: [#item{}],
    ExpireFlag :: boolean().%% 是否可删除过期物品()
del(Flag, Package, ItemInfo) ->
    del(Flag, Package, ItemInfo, true).
del(by_id, Package, ItemInfo, ExpireFlag) ->
    del_by_id(Package, ItemInfo, ExpireFlag);
del(by_base_id, Package, ItemInfo, ExpireFlag) ->
    del_by_base_id(Package, ItemInfo, ExpireFlag);
del(by_base_bind_id, Package, ItemInfo, ExpireFlag) ->
    del_by_base_bind_id(Package, ItemInfo, ExpireFlag);
del(by_group, Package, ItemInfo, ExpireFlag) ->
    del_by_group(Package, ItemInfo, ExpireFlag);
del(by_base_id_all, Package, ItemInfo, ExpireFlag) ->
    del_all_by_base_id(Package, ItemInfo, ExpireFlag).


%% @doc 按照ID查询物品
-spec fetch(Pack, pos_integer(), #role{}) -> {ok, #item{}} | false when
    Pack :: ?package_type_bag | ?package_type_store.
fetch(Type, Id, Role) ->
    case type_to_package(Type, Role) of
        #package{items = Items} ->
            case lists:keyfind(Id, #item.id, Items) of
                Item = #item{id = Id} -> {ok, Item};
                false -> false
            end;
        _ ->
            false

    end.

%% @doc 查找物品, 唯一键值的物品
-spec find(Mode, integer(), #package{}) -> false | {ok, #item{}} when
    Mode :: by_id | by_type | by_pos.
find(by_id, Id, #package{items = Items}) ->
    case lists:keyfind(Id, #item.id, Items) of
        Item = #item{id = Id} -> {ok, Item};
        false -> false
    end;
find(by_pos, Pos, #package{items = Items}) ->
    case lists:keyfind(Pos, #item.pos, Items) of
        Item = #item{pos = Pos} -> {ok, Item};
        false -> false
    end.

%% @doc 统计物品，非唯一键值的物品
-spec count(Mode, integer(), #package{}) -> {[#item{}] | [], non_neg_integer()} when
    Mode :: by_group | by_base_id | by_type.
count(by_group, BaseId, #package{items = Items}) ->
    do_count(by_group, BaseId, Items);
count(by_base_id, BaseId, #package{items = Items}) ->
    do_count(by_base_id, BaseId, Items);
count(by_type, Type, #package{items = Items}) ->
    do_count(by_type, Type, Items).

count_bind(by_base_bind_id, BaseId, Bind, #package{items = Items}) ->
    do_count_bind(by_base_bind_id, BaseId, Bind, Items).

%% @doc 查找背包中绑定物品与非绑定物品
-spec find_bind_unbind(BaseId :: non_neg_integer(), #package{}) -> {BindItems, UnBindItems, BindNum, UnBindNum} when
    BindItems :: [#item{}],
    UnBindItems :: [#item{}],
    BindNum :: non_neg_integer(),
    UnBindNum :: non_neg_integer().
find_bind_unbind(BaseId, #package{items = Items}) ->
    do_find_bind_unbind(Items, BaseId, [], [], 0, 0).
do_find_bind_unbind([], _BaseId, BindItems, UnBindItems, BindNum, UnBindNum) ->
    {BindItems, UnBindItems, BindNum, UnBindNum};
do_find_bind_unbind([Item = #item{bind = ?true, quantity = N, base_id = BaseId} | T], BaseId, BindItems, UnBindItems, BindNum, UnBindNum) ->
    do_find_bind_unbind(T, BaseId, [Item | BindItems], UnBindItems, BindNum + N, UnBindNum);
do_find_bind_unbind([Item = #item{quantity = N, base_id = BaseId} | T], BaseId, BindItems, UnBindItems, BindNum, UnBindNum) ->
    do_find_bind_unbind(T, BaseId, BindItems, [Item | UnBindItems], BindNum, UnBindNum + N);
do_find_bind_unbind([_ | T], BaseId, BindItems, UnBindItems, BindNum, UnBindNum) ->
    do_find_bind_unbind(T, BaseId, BindItems, UnBindItems, BindNum, UnBindNum).

%% @doc 更新某个物品在包裹中位置,限定于BASEID不改变的情况，就是物品本质不变，属性改变情况，产生更新消息
-spec fresh_item(#item{}, #item{}, #package{}, #role{}) -> {ok, #package{}, #item{}}.
fresh_item(OldItem, NewItem, Package = #package{type = PackType, free_cell = FreeCell, items = Items}, Role) ->
    NewItems = lists:keyreplace(OldItem#item.id, #item.id, Items, NewItem),
    push_item_info(update, Role, [{PackType, NewItem}]),
    case NewItem#item.pos =:= OldItem#item.pos of
        true ->
            {ok, Package#package{items = NewItems}, NewItem};
        false ->
            NewFreeCell = lists:sort([OldItem#item.pos | (FreeCell -- [NewItem#item.pos])]),
            {ok, Package#package{items = NewItems, free_cell = NewFreeCell}, NewItem}
    end;
fresh_item(_, _, _, _) -> false.


%% @doc 更换某个物品，跟fresh_item类似，但限定于BASEID改变的情况，就是物品本身改变，产生增删消息
-spec replace_item(#item{}, #item{}, #package{}, #role{}) -> {ok, #package{}, #item{}}.
replace_item(OldItem, NewItem, Pack = #package{type = PackType, free_cell = FreeCell, items = Items}, Role) ->
    NewItems = lists:keyreplace(OldItem#item.id, #item.id, Items, NewItem),
    push_item_info(del, Role, [{PackType, OldItem}]),
    push_item_info(add, Role, [{PackType, NewItem}]),
    case NewItem#item.pos =:= OldItem#item.pos of
        true ->
            {ok, Pack#package{items = NewItems}, NewItem};
        false ->
            NewFreeCell = lists:sort([OldItem#item.pos | (FreeCell -- [NewItem#item.pos])]),
            {ok, Pack#package{items = NewItems, free_cell = NewFreeCell}, NewItem}
    end;
replace_item(_, _, _, _) -> false.


%% @doc 单物品推送通知
-spec push_item_info(Mode, Send, ItemList) -> ok when
    Mode :: add | del | update,
    Send :: #role{} | pid() | #link{},
    ItemList :: [{PackageType, #item{}}] | [{PackageType, [#item{}]}],
    PackageType :: ?package_type_bag | ?package_type_store.
push_item_info(Mode, #role{link = #link{conn_pid = ConnPid}}, ItemList) ->
    do_send_info(Mode, ConnPid, ItemList, []);
push_item_info(Mode, ConnPid, ItemList) when is_pid(ConnPid) ->
    do_send_info(Mode, ConnPid, ItemList, []);
push_item_info(Mode, #link{conn_pid = ConnPid}, ItemList) ->
    do_send_info(Mode, ConnPid, ItemList, []);
push_item_info(_Mode, _Send, _Info) ->
    ?ERR("错误的参数结构，无法推送物品更新通知[_Mode:~w, _Send:~w, _Info:~w", [_Mode, _Send, _Info]),
    ok.

%% @doc 拆分物品
-spec split_item(Mode, #role{}, #item{}, non_neg_integer()) -> {ok, #role{}} | {false, bitstring()} when
    Mode :: bag | store.
split_item(Type, Role = #role{link = #link{conn_pid = ConnPid}}, Item = #item{quantity = Q, pos = Pos}, Num) when Q >= Num ->
    case type_to_package(Type, Role) of
        Bag = #package{items = Items, next_id = NextId, free_cell = FreeCell} when FreeCell =/= [] ->
            [NewCell | P] = FreeCell,
            NewAddItem = Item#item{id = NextId, quantity = Num, pos = NewCell},
            NewItem = Item#item{quantity = Q - Num},
            {NewItems, NewFreeCell} =
                case Q =:= Num of
                    true ->
                        {[NewAddItem | lists:keydelete(Item#item.id, #item.id, Items)], [Pos | P]};
                    false ->
                        {[NewAddItem | lists:keyreplace(Item#item.id, #item.id, Items, NewItem)], P}
                end,
            case Q =:= Num of
                true -> push_item_info(del, ConnPid, [{Type, NewItem}]);
                false -> push_item_info(update, ConnPid, [{Type, NewItem}])
            end,
            push_item_info(add, ConnPid, [{Type, NewAddItem}]),
            NewBag = Bag#package{items = NewItems, next_id = NextId + 1, free_cell = lists:sort(NewFreeCell)},
            %% 保存背包
            NewRole = update_role_package(Type, NewBag, Role),
            {ok, NewRole};
        _ ->
            {false, ""}
    end;
split_item(_, _, _, _) -> {false, ""}.

%% @doc 损益推送通知
-spec push_gain(GainList, #role{}) -> ok when
    GainList :: [{Type, Add, Del, Update}],
    Type :: ?package_type_bag,
    Add :: [#item{}],
    Del :: [#item{}],
    Update :: [#item{}].
push_gain([], _Role) -> ok;
push_gain([{Type, Add, Del, Update} | T], Role) ->
    push_item_info(del, Role, [{Type, Del}]),
    push_item_info(add, Role, [{Type, Add}]),
    push_item_info(update, Role, [{Type, Update}]),
    push_gain(T, Role).

%% ------------------------------------------------
%% 推送物品相关类消息
%% ------------------------------------------------
do_send_info(_Mode, _ConnPid, [], []) -> skip;
do_send_info(add, ConnPid, [], SendList) ->
    server_conn:pack_send(ConnPid, 10310, {lists:reverse(SendList)}),
    ok;
do_send_info(add, ConnPid, [{PackageType, Item = #item{}} | T], SendList) ->
    NewSendList = [{PackageType, Item} | SendList],
    do_send_info(add, ConnPid, T, NewSendList);
do_send_info(add, ConnPid, [{PackageType, Items} | T], SendList) when is_list(Items) ->
    NewItemInfo = [{PackageType, Item} || Item <- Items],
    do_send_info(add, ConnPid, T, NewItemInfo ++ SendList);

do_send_info(del, ConnPid, [], SendList) ->
    server_conn:pack_send(ConnPid, 10311, {lists:reverse(SendList)}),
    ok;
do_send_info(del, ConnPid, [{PackageType, Item = #item{}} | T], SendList) ->
    NewSendList = [{PackageType, Item} | SendList],
    do_send_info(del, ConnPid, T, NewSendList);
do_send_info(del, ConnPid, [{PackageType, Items} | T], SendList) when is_list(Items) ->
    NewItemInfo = [{PackageType, Item} || Item <- Items],
    do_send_info(del, ConnPid, T, NewItemInfo ++ SendList);

do_send_info(update, ConnPid, [], SendList) ->
    server_conn:pack_send(ConnPid, 10312, {SendList}),
    ok;
do_send_info(update, ConnPid, [{PackageType, Item = #item{}} | T], SendList) ->
    NewSendList = [{PackageType, Item} | SendList],
    do_send_info(update, ConnPid, T, NewSendList);
do_send_info(update, ConnPid, [{PackageType, Items} | T], SendList) when is_list(Items) ->
    NewItemInfo = [{PackageType, Item} || Item <- Items],
    do_send_info(update, ConnPid, T, NewItemInfo ++ SendList).

%% ------------------------------------------------
%% 统计
%% ------------------------------------------------
do_count(Mode, Key, Items) ->
    do_count(Mode, Key, Items, [], 0).

do_count(_, _, [], Result, Num) -> {Result, Num};
do_count(by_base_id, BaseId, [Item = #item{base_id = BaseId, quantity = Quantity} | T], Result, Num) ->
    do_count(by_base_id, BaseId, T, [Item | Result], Num + Quantity);
do_count(by_group, Group, [Item = #item{group = Group, quantity = Quantity} | T], Result, Num) ->
    do_count(by_group, Group, T, [Item | Result], Num + Quantity);
do_count(by_type, Type, [Item = #item{type = Type, quantity = Quantity} | T], Result, Num) ->
    do_count(by_type, Type, T, [Item | Result], Num + Quantity);
do_count(Mode, Key, [_ | T], Result, Num) ->
    do_count(Mode, Key, T, Result, Num).

%% ------------------------------------------------
%% 统计 绑定
%% ------------------------------------------------
do_count_bind(Mode, Key, Bind, Items) ->
    do_count_bind(Mode, Key, Bind, Items, [], 0).

do_count_bind(_, _, _, [], Result, Num) -> {Result, Num};
do_count_bind(by_base_bind_id, BaseId, Bind, [Item = #item{base_id = BaseId, bind = Bind, quantity = Quantity} | T], Result, Num) ->
    do_count_bind(by_base_bind_id, BaseId, Bind, T, [Item | Result], Num + Quantity);
do_count_bind(Mode, Key, Bind, [_ | T], Result, Num) ->
    do_count_bind(Mode, Key, Bind, T, Result, Num).

%% ------------------------------------------------
%% 添加删除
%% ------------------------------------------------

%% @doc 增加物品列表，但是不带通知
add_no_push_items(bag, Role = #role{p_bag = Bag}, Items) ->
    do_add_no_push_items(Bag, Items, Role, #{new => [], add => [], update => []}).

add_no_push_base_id(bag, Role = #role{p_bag = Bag}, Items) ->
    do_add_no_push_base_id(Bag, Items, Role, []).

do_add_no_push_items(Package, [], _Role, AddItems) -> {ok, Package, AddItems};
do_add_no_push_items(Package, [H | T], Role, AddItems) ->
    case do_add(Package, H, Role, AddItems) of
        full -> full;
        false -> false;
        {ok, NewPackage, NewAddItems} ->
            do_add_no_push_items(NewPackage, T, Role, NewAddItems)
    end.

%% @doc 增加BASEID物品，但是不带通知
do_add_no_push_base_id(Package, [], Role, Items) ->
    do_add_no_push_items(Package, Items, Role, #{new => [], add => [], update => []});
do_add_no_push_base_id(Package, [{BaseId, Bind, Num} | T], Role = #role{}, Items) ->
    case item:make(BaseId, Bind, Num) of
        false ->
            ?DEBUG("不存在的物品: ~w", [BaseId]),
            false;
        {ok, NewItems} ->
            do_add_no_push_base_id(Package, T, Role, NewItems ++ Items)
    end;
do_add_no_push_base_id(Package, [H = #{base_id := _BaseId, bind := _Bind, quantity := _Num} | T], Role, Items) ->
    case item:make(H) of
        false -> false;
        {ok, NewItems} ->
            do_add_no_push_base_id(Package, T, Role, NewItems ++ Items)
    end;
do_add_no_push_base_id(_Package, [_ | _T], _Role, _Items) ->
    false.


%% @doc 按照ID删除物品
%% 删除装备栏的比较特殊，要特殊处理
del_by_id(Package, ItemInfo, _ExpireFlag) ->
    do_del_by_id(Package, ItemInfo, [], []).
do_del_by_id(Package, [], DelList, FreshList) ->
    {ok, Package, DelList, FreshList};
do_del_by_id(Package, [{ItemId, Num} | T], DelList, FreshList) ->
    case do_del_by_id(Package, ItemId, Num, DelList, FreshList) of
        {false, Reason} -> {false, Reason};
        {ok, NewPackage, NewDelList, NewFreshList} ->
            do_del_by_id(NewPackage, T, NewDelList, NewFreshList)
    end.

do_del_by_id(Package = #package{free_cell = FreeCell, items = Items}, ItemId, Num, DelList, FreshList)
    when Num > 0 ->
    SortItem = lists:sort(fun sort_item_by_bind/2, Items),
    case do_del_by_id(SortItem, [], ItemId, [], Num, DelList, FreshList) of
        {false, Reason} -> {false, Reason};
        {ok, NewItems, NewFreeCell, NewDelList, NewFreshList} ->
            F = lists:sort(NewFreeCell ++ FreeCell),
            {ok, Package#package{free_cell = F, items = NewItems}, NewDelList, NewFreshList}
    end;
do_del_by_id(_Package, _, _, _, _) -> {false, ?T("无法扣除0个物品")}.

do_del_by_id([], _Items, _ItemId, _NewFreeCell, _Num, _DelList, _FreshList) -> {false, ?T("未发现物品")};
do_del_by_id([Item = #item{id = Fid, quantity = Q, pos = Pos} | T], Items, Fid, NewFreeCell, Num, DelList, FreshList) ->
    N = Q - Num,
    if
        N =:= 0 ->
            {ok, T ++ Items, [Pos | NewFreeCell], [Item | DelList], FreshList};
        N > 0 ->
            {ok, [Item#item{quantity = N} | T] ++ Items, NewFreeCell, DelList, [Item#item{quantity = N} | FreshList]};
        true ->
            {false, ?T("数量不足，无法扣除")}
    end;
do_del_by_id([Item | T], Items, Id, NewFreeCell, Num, DelList, FreshList) ->
    do_del_by_id(T, [Item | Items], Id, NewFreeCell, Num, DelList, FreshList).


%% @doc 按照BASEID删除对应全部物品,无视BIND与非BIND,无视过期
del_all_by_base_id(Package, ItemInfo, _ExpireFlag) ->
    do_del_all_by_base_id(Package, ItemInfo, []).
do_del_all_by_base_id(Package = #package{free_cell = FreeCell}, [], DelList) ->
    NewFreeCell = lists:sort(FreeCell),
    {ok, Package#package{free_cell = NewFreeCell}, DelList};
do_del_all_by_base_id(Package = #package{free_cell = FreeCell, items = Items}, [BaseId | T], DelList) ->
    Fun = fun(I = #item{base_id = IB, pos = Pos}, {ItemL, DelL, FreeL}) ->
        case IB of
            BaseId ->
                {ItemL, [I | DelL], [Pos | FreeL]};
            _ ->
                {[I | ItemL], DelL, FreeL}
        end
          end,
    {NewItems, NewDelList, NewFreeCell} = lists:foldl(Fun, {[], DelList, FreeCell}, Items),
    F = NewFreeCell,
    do_del_all_by_base_id(Package#package{free_cell = F, items = NewItems}, T, NewDelList).

%% @doc 按照BASEID删除物品，无视BIND与非BIND
del_by_base_id(Package, ItemInfo, _ExpireFlag) ->
    Now = date:unixtime(),
    do_del_by_base_id(Package, ItemInfo, Now, [], []).
do_del_by_base_id(Package, [], _Now, DelList, FreshList) -> {ok, Package, DelList, FreshList};
do_del_by_base_id(Package, [{BaseId, Num} | T], Now, DelList, FreshList) ->
    case do_del_by_base_id(Package, BaseId, Num, Now, DelList, FreshList) of
        {false, Reason} -> {false, Reason};
        {ok, NewPackage, NewDelList, NewFreshList} ->
            do_del_by_base_id(NewPackage, T, Now, NewDelList, NewFreshList)
    end.

do_del_by_base_id(Package = #package{free_cell = FreeCell, items = Items}, BaseId, Num, Now, DelList, FreshList) when Num > 0 ->
    SortItem1 = lists:sort(fun sort_item_by_bind/2, Items),
    case do_del_by_base_id(SortItem1, [], BaseId, [], Num, Now, DelList, FreshList) of
        {false, Reason} -> {false, Reason};
        {ok, NewItems, NewFreeCell, NewDelList, NewFreshList} ->
            F = lists:sort(NewFreeCell ++ FreeCell),
            {ok, Package#package{free_cell = F, items = NewItems}, NewDelList, NewFreshList}
    end;
do_del_by_base_id(_Package, _, _, _, _, _) -> {false, ?T("无法扣除0个物品")}.

do_del_by_base_id([], _Items, BaseId, _NewFreeCell, Num, _Now, _DelList, _FreshList) when Num > 0 ->
    {false, util:flist(?T("物品[~ts]不足"), [item:attr(name, BaseId)])};
do_del_by_base_id([Item = #item{base_id = BaseId, quantity = Q, pos = Pos, expire_time = ExpireTime} | T], Items, BaseId, NewFreeCell, Num, Now, DelList, FreshList)
    when ExpireTime =< 0 orelse ExpireTime >= Now ->
    N = Q - Num,
    if
        N =:= 0 ->
            {ok, T ++ Items, [Pos | NewFreeCell], [Item | DelList], FreshList};
        N > 0 ->
            {ok, [Item#item{quantity = N} | T] ++ Items, NewFreeCell, DelList, [Item#item{quantity = N} | FreshList]};
        true ->
            do_del_by_base_id(T, Items, BaseId, [Pos | NewFreeCell], Num - Q, Now, [Item | DelList], FreshList)
    end;
do_del_by_base_id([Item | T], Items, BaseId, NewFreeCell, Num, Now, DelList, FreshList) ->
    do_del_by_base_id(T, [Item | Items], BaseId, NewFreeCell, Num, Now, DelList, FreshList).

% @doc 按照BASEID删除物品，区分Bind
del_by_base_bind_id(Package, ItemInfo, _ExpireFlag) ->
    do_del_by_base_bind_id(Package, ItemInfo, [], []).
do_del_by_base_bind_id(Package, [], DelList, FreshList) -> {ok, Package, DelList, FreshList};
do_del_by_base_bind_id(Package, [{BaseId, Bind, Num} | T], DelList, FreshList) ->
    case do_del_by_base_bind_id(Package, BaseId, Bind, Num, DelList, FreshList) of
        {false, Reason} -> {false, Reason};
        {ok, NewPackage, NewDelList, NewFreshList} ->
            do_del_by_base_bind_id(NewPackage, T, NewDelList, NewFreshList)
    end.

% @doc 按照物品组从小到达删除物品，按base_id从小到达排列
del_by_group(Package, ItemInfo, _ExpireFlag) ->
    do_del_by_group(Package, ItemInfo, [], []).
do_del_by_group(Package, [], DelList, FreshList) -> {ok, Package, DelList, FreshList};
do_del_by_group(Package, [{BaseId, Num} | T], DelList, FreshList) ->
    case do_del_by_group(Package, BaseId, Num, DelList, FreshList) of
        {false, Reason} -> {false, Reason};
        {ok, NewPackage, NewDelList, NewFreshList} ->
            do_del_by_group(NewPackage, T, NewDelList, NewFreshList)
    end.

do_del_by_group(Package = #package{free_cell = FreeCell, items = Items}, BaseId, Num, DelList, FreshList) when Num > 0 ->
    SortItem1 = lists:sort(fun sort_group/2, Items),
    ItemGroup = item:attr(group, BaseId),
    case do_del_by_group(SortItem1, [], ItemGroup, [], Num, DelList, FreshList) of
        {false, Reason} -> {false, Reason};
        {ok, NewItems, NewFreeCell, NewDelList, NewFreshList} ->
            F = lists:sort(NewFreeCell ++ FreeCell),
            {ok, Package#package{free_cell = F, items = NewItems}, NewDelList, NewFreshList}
    end;
do_del_by_group(_Package, _, _, _, _) -> {false, ?T("无法扣除0个物品")}.

do_del_by_group(_BagItems, _Items, 0, _NewFreeCell, _Num, _DelList, _FreshList) ->
    {false, util:flist(?T("物品组不存在"))};
do_del_by_group([], _Items, BaseId, _NewFreeCell, Num, _DelList, _FreshList) when Num > 0 ->
    Msg = notice:format(?T("物品~ts不足"), [{item_2, BaseId, Num}]),
    {false, util:flist(Msg)};
do_del_by_group([Item = #item{group = Group, quantity = Q, pos = Pos, expire_type = ExpireType, expire_time = ExpireSec} | T], Items, Group, NewFreeCell, Num, DelList, FreshList) ->
    Now = date:unixtime(),
    CanUse =
        if
            ExpireType =:= ?item_expire_starttime orelse ExpireType =:= ?item_expire_startdate -> Now >= ExpireSec;
            ExpireType =:= ?item_expire_null -> true;
            true -> Now < ExpireSec
        end,
    case CanUse of
        true ->
            N = Q - Num,
            if
                N =:= 0 ->
                    {ok, T ++ Items, [Pos | NewFreeCell], [Item | DelList], FreshList};
                N > 0 ->
                    {ok, [Item#item{quantity = N} | T] ++ Items, NewFreeCell, DelList, [Item#item{quantity = N} | FreshList]};
                true ->
                    do_del_by_group(T, Items, Group, [Pos | NewFreeCell], Num - Q, [Item | DelList], FreshList)
            end;
        false ->
            do_del_by_group(T, [Item | Items], Group, NewFreeCell, Num, DelList, FreshList)
    end;
do_del_by_group([Item | T], Items, Group, NewFreeCell, Num, DelList, FreshList) ->
    do_del_by_group(T, [Item | Items], Group, NewFreeCell, Num, DelList, FreshList).

do_del_by_base_bind_id(Package = #package{free_cell = FreeCell, items = Items}, BaseId, Bind, Num, DelList, FreshList) when Num > 0 ->
    SortItem1 = lists:sort(fun sort_item_by_bind/2, Items),
    case do_del_by_base_bind_id(SortItem1, [], BaseId, Bind, [], Num, DelList, FreshList) of
        {false, Reason} -> {false, Reason};
        {ok, NewItems, NewFreeCell, NewDelList, NewFreshList} ->
            F = lists:sort(NewFreeCell ++ FreeCell),
            {ok, Package#package{free_cell = F, items = NewItems}, NewDelList, NewFreshList}
    end;
do_del_by_base_bind_id(_Package, _, _, _, _, _) -> {false, ?T("无法扣除0个物品")}.

do_del_by_base_bind_id([], _Items, BaseId, _Bind, _NewFreeCell, Num, _DelList, _FreshList) when Num > 0 ->
    {false, util:flist(?T("物品[~ts]不足"), [item:attr(name, BaseId)])};
do_del_by_base_bind_id([Item = #item{base_id = BaseId, bind = Bind, quantity = Q, pos = Pos} | T], Items, BaseId, Bind, NewFreeCell, Num, DelList, FreshList) ->
    N = Q - Num,
    if
        N =:= 0 ->
            {ok, T ++ Items, [Pos | NewFreeCell], [Item | DelList], FreshList};
        N > 0 ->
            {ok, [Item#item{quantity = N} | T] ++ Items, NewFreeCell, DelList, [Item#item{quantity = N} | FreshList]};
        true ->
            do_del_by_base_bind_id(T, Items, BaseId, Bind, [Pos | NewFreeCell], Num - Q, [Item | DelList], FreshList)
    end;
do_del_by_base_bind_id([Item | T], Items, BaseId, Bind, NewFreeCell, Num, DelList, FreshList) ->
    do_del_by_base_bind_id(T, [Item | Items], BaseId, Bind, NewFreeCell, Num, DelList, FreshList).


%% -----------------------------------------
%% 整理
%% -----------------------------------------

%% @doc 给排序后之后的物品进行编号
add_new_pos(SortItem, FreeCell) ->
    add_new_pos(SortItem, FreeCell, []).
add_new_pos([], FreeCell, NewItems) -> {FreeCell, NewItems};
add_new_pos(_, FreeCell = [], NewItems) -> {FreeCell, NewItems};
add_new_pos([I | T], [Pos | FreeCell], NewItems) ->
    add_new_pos(T, FreeCell, [I#item{pos = Pos} | NewItems]).

%% @doc 检测
check_sort_result(Role, PackageType, Items, NewItems) ->
    do_check_sort_result(Role, PackageType, Items, NewItems, [], []).

do_check_sort_result(Role, PackageType, [], _NewItems, FreshList, DelList) ->
    push_item_info(del, Role, [{PackageType, DelList}]),
    push_item_info(update, Role, [{PackageType, FreshList}]),
    ok;
do_check_sort_result(Role, PackageType, [Item = #item{id = Id, quantity = Quantity, pos = Pos} | T], NewItems, FreshList, DelList) ->
    case lists:keyfind(Id, #item.id, NewItems) of
        false ->
            do_check_sort_result(Role, PackageType, T, NewItems, FreshList, [Item | DelList]);
        #item{id = Id, quantity = Quantity, pos = Pos} -> %% 完全相同的物品
            do_check_sort_result(Role, PackageType, T, NewItems, FreshList, DelList);
        NewItem = #item{quantity = Quantity1, pos = Pos1} when Quantity =/= Quantity1 orelse Pos =/= Pos1 ->
            do_check_sort_result(Role, PackageType, T, NewItems, [NewItem | FreshList], DelList);
        _ ->
            do_check_sort_result(Role, PackageType, T, NewItems, FreshList, DelList)
    end.

%% @doc 合并物品
combine([], Rtn) -> lists:reverse(Rtn);
combine([I = #item{} | T], Rtn) ->
    combine(T, [I | Rtn]).

%% @doc 合并物品
merge(List) ->
    merge(List, []).
merge([], Rtn) -> Rtn;
merge([{BaseId, Q} | T], Rtn) ->
    NewRtn = do_merge(Rtn, BaseId, Q, []),
    merge(T, NewRtn).

do_merge([], BaseId, Q, NewRtn) -> [{BaseId, Q} | NewRtn];
do_merge([{BaseId, N} | T], BaseId, Q, NewRtn) ->
    lists:reverse(NewRtn) ++ [{BaseId, N + Q} | T];
do_merge([{BaseId2, N} | T], BaseId, Q, NewRtn) ->
    do_merge(T, BaseId, Q, [{BaseId2, N} | NewRtn]).

%% @doc 合并绑定物品
merge_bind(List) ->
    merge_bind(List, []).
merge_bind([], Rtn) -> Rtn;
merge_bind([{BaseId, Bind, Q} | T], Rtn) ->
    NewRtn = do_merge_bind(Rtn, BaseId, Bind, Q, []),
    merge_bind(T, NewRtn).

do_merge_bind([], BaseId, Bind, Q, NewRtn) -> [{BaseId, Bind, Q} | NewRtn];
do_merge_bind([{BaseId, Bind, N} | T], BaseId, Bind, Q, NewRtn) ->
    lists:reverse(NewRtn) ++ [{BaseId, Bind, N + Q} | T];
do_merge_bind([{BaseId2, Bind, N} | T], BaseId, Bind, Q, NewRtn) ->
    do_merge_bind(T, BaseId, Bind, Q, [{BaseId2, N} | NewRtn]).

%% 排序

sort_type(Item1 = #item{type = Type}, Item2 = #item{type = Type}) ->
    sort_baseid(Item1, Item2);
sort_type(#item{type = T1}, #item{type = T2}) ->
    do_sort_type(T1, T2);
sort_type(_, _) -> false.

%% @doc 特殊的排序规则
do_sort_type(T1, T2) ->
    T1 > T2.


sort_baseid(#item{base_id = BaseId1}, #item{base_id = BaseId2}) when BaseId1 < BaseId2 -> true;
sort_baseid(Item1 = #item{expire_type = ExpireType, base_id = BaseId}, Item2 = #item{base_id = BaseId}) when ExpireType =/= ?item_expire_null ->
    sort_use(Item1, Item2);%% 限时物品排序
sort_baseid(Item1 = #item{base_id = BaseId}, Item2 = #item{base_id = BaseId}) ->
    sort_item_by_bind(Item1, Item2);%%普通物品排序
sort_baseid(_, _) -> false.

%% 按物品组排序
sort_group(#item{group = Group1}, #item{group = Group2}) when Group1 < Group2 -> true;
sort_group(Item1 = #item{group = Group}, Item2 = #item{group = Group}) ->
    sort_expire(Item1, Item2);%%普通物品排序
sort_group(_, _) -> false.

%%@ 时间类型
%% 情况1 普通 + 开启
%% 情况2 普通 + 过期
%% 情况3 开启 + 普通
%% 情况4 过期 + 普通
%% 情况5 开启 + 开启
%% 情况6 普通 + 普通
%% 情况7 过期 + 过期
%% 情况8 过期 + 开启
%% 情况9 开启 + 过期
sort_expire(Item1 = #item{expire_type = ?item_expire_null}, Item2 = #item{expire_type = ExpireType2, expire_time = ExpireTime2}) ->
    Now = date:unixtime(),
    if
        ExpireType2 =:= ?item_expire_starttime orelse ExpireType2 =:= ?item_expire_startdate -> %% 到期开启道具
            if Now >= ExpireTime2 -> sort_item_by_bind(Item1, Item2); %% 开启时间已过, 都是普通道具
                true -> true   %物品1可使用, 物品二未开启
            end;
        ExpireType2 =:= ?item_expire_endtime orelse ExpireType2 =:= ?item_expire_enddate orelse ExpireType2 =:= ?item_expire_puton_enddate orelse ExpireType2 =:= ?item_expire_puton_endtime -> %% 到期过期道具
            if Now < ExpireTime2 -> false; %% 未过期，优先使用
                true -> true   % 已过期 排到后面
            end;
        true -> sort_item_by_bind(Item1, Item2)    %% 都是普通道具
    end;
sort_expire(Item1 = #item{expire_type = ExpireType1, expire_time = ExpireTime1}, Item2 = #item{expire_type = ExpireType2, expire_time = ExpireTime2}) when ExpireType1 =:= ?item_expire_starttime orelse ExpireType1 =:= ?item_expire_startdate ->
    Now = date:unixtime(),
    if ExpireType2 =:= ?item_expire_starttime orelse ExpireType2 =:= ?item_expire_startdate ->
        if Now >= ExpireTime1 andalso Now >= ExpireTime2 -> sort_item_by_bind(Item1, Item2);    %% 物品1:开启,物品2:开启
            Now >= ExpireTime1 andalso Now < ExpireTime2 -> true;   %% 物品1:开启,物品2:未开启
            Now < ExpireTime1 andalso Now >= ExpireTime2 -> false;  %% 物品1:未开启,物品2:开启
            true -> sort_item_by_bind(Item1, Item2) %%未开启物品
        end;
        ExpireType2 =:= ?item_expire_endtime orelse ExpireType2 =:= ?item_expire_enddate orelse ExpireType2 =:= ?item_expire_puton_enddate orelse ExpireType2 =:= ?item_expire_puton_endtime ->
            if Now =< ExpireTime2 -> false;    % 物品2未过期
                true -> true % 物品2已过期
            end;
        true -> false  %% 1是开启物品 2是普通道具 先用普通道具吧
    end;
sort_expire(Item1 = #item{expire_type = ExpireType1, expire_time = ExpireTime1}, Item2 = #item{expire_type = ExpireType2, expire_time = ExpireTime2}) when ExpireType1 =:= ?item_expire_endtime orelse ExpireType1 =:= ?item_expire_enddate orelse ExpireType1 =:= ?item_expire_puton_enddate orelse ExpireType1 =:= ?item_expire_puton_endtime ->  %% 道具1已过期
    Now = date:unixtime(),
    if
        ExpireType2 =:= ?item_expire_endtime orelse ExpireType2 =:= ?item_expire_enddate orelse ExpireType2 =:= ?item_expire_puton_enddate orelse ExpireType2 =:= ?item_expire_puton_endtime ->
            if Now < ExpireTime1 andalso Now < ExpireTime2 -> sort_expire_time(Item1, Item2);    % 物品1:未过期,物品2:未过期
                Now < ExpireTime1 andalso Now >= ExpireTime2 -> true;  % 物品1:未过期,物品2:过期
                Now >= ExpireTime1 andalso Now < ExpireTime2 -> false;  % 物品1:过期,物品2:未过期
                true -> sort_item_by_bind(Item1, Item2) %都不能用
            end;
        true ->
            if Now >= ExpireTime1 -> false;    %% 物品1:过期
                true -> true %% %% 物品1:未过期
            end
    end;
sort_expire(_, _) -> false.

%%@ 时间类型
%%按物品是否可使用排序
%%再按是否绑定排序
%%最后按过期时间排序
%%@ 普通物品
%%按绑定和非绑定
%%按id排序
sort_use(Item1 = #item{expire_type = ExpireType, expire_time = ExpireTime1}, Item2 = #item{expire_time = ExpireTime2}) ->
    Now = date:unixtime(),
    if ExpireType =:= ?item_expire_starttime orelse ExpireType =:= ?item_expire_startdate ->
        if Now >= ExpireTime1 andalso Now >= ExpireTime2 -> sort_item_by_bind(Item1, Item2);
            Now >= ExpireTime1 andalso Now < ExpireTime2 -> true;   %物品1可使用
            Now < ExpireTime1 andalso Now >= ExpireTime2 -> false;  %物品2可使用
            true -> sort_item_by_bind(Item1, Item2) %%未开启物品
        end;
        ExpireType =:= ?item_expire_endtime orelse ExpireType =:= ?item_expire_enddate orelse ExpireType =:= ?item_expire_puton_enddate orelse ExpireType =:= ?item_expire_puton_endtime ->
            if Now < ExpireTime1 andalso Now < ExpireTime2 -> sort_item_by_bind(Item1, Item2);
                Now =< ExpireTime1 andalso Now > ExpireTime2 -> true;   %物品1可使用
                Now > ExpireTime1 andalso Now =< ExpireTime2 -> false;  %物品2可使用
                true -> sort_item_by_bind(Item1, Item2) %%过期物品
            end;
        true -> false
    end;
sort_use(_, _) -> false.

%% 排序
sort_item_by_bind(#item{bind = Bind1}, #item{bind = Bind2}) when Bind1 > Bind2 -> true;
sort_item_by_bind(Item1 = #item{bind = Bind}, Item2 = #item{bind = Bind}) ->
    sort_expire_time(Item1, Item2);
sort_item_by_bind(_, _) -> false.

sort_expire_time(#item{expire_time = ExpireTime1}, #item{expire_time = ExpireTime2}) when ExpireTime1 =/= ExpireTime2 ->
    ExpireTime1 < ExpireTime2;  %限时物品
sort_expire_time(Item1 = #item{expire_time = ExpireTime1}, Item2 = #item{expire_time = ExpireTime2}) when ExpireTime1 =:= ExpireTime2 ->
    sort_id(Item1, Item2);%限时相同和普通物品
sort_expire_time(_, _) -> false.

sort_id(#item{id = Id1}, #item{id = Id2}) when Id1 < Id2 -> true;
sort_id(_, _) -> false.


%% @doc 根据物品bid 查取数量
find_bind_num(Bid, Bind, Type, Role) ->
    case type_to_package(Type, Role) of
        #package{items = Items} ->
            find_bind_num(Bid, Bind, Items);
        _ ->
            0
    end.


%% @doc 获取绑定的道具数量
find_bind_num(Bid, Bind, Items) ->
    lists:sum(
        [I#item.quantity || I <- Items, I#item.bind =:= Bind andalso I#item.base_id =:= Bid]
    ).

%% @doc 根据物品bid 查取数量
find_num(Bid, Type, Role) ->
    case type_to_package(Type, Role) of
        #package{items = Items} ->
            find_num(Bid, Items);
        _ ->
            0
    end.

%% @doc 查找数量
find_num(Bid, Items) ->
    lists:sum(
        [I#item.quantity || I <- list_util:keyfind_all(Bid, #item.base_id, Items)]
    ).

%% @doc 根据物品组 查取数量
find_group(Group, Type, Role = #role{}) ->
    case type_to_package(Type, Role) of
        #package{items = Items} ->
            find_group(Group, Items);
        _ ->
            0
    end.

%% @doc 根据物品组查找数量
find_group(Group, Items) ->
    Fun = fun(Item) ->
        case item:check_expire(Item) of
            true -> false;
            false ->
                case item:check_start(Item) of
                    true -> true;
                    false -> false
                end
        end
          end,
    lists:sum(
        [I#item.quantity || I <- list_util:keyfind_all(Group, #item.group, Items), Fun(I)]
    ).


%% @doc 返回包裹空格子数量
free_cell_num(Role = #role{}, Type) ->
    case type_to_package(Type, Role) of
        #package{free_cell = Cells} -> length(Cells);
        _ ->
            0
    end.


%% @doc 物品转为绑定
items_change_bind(Role = #role{}, ItemIds, Type) ->
    case type_to_package(Type, Role) of
        Package = #package{} ->
            items_change_bind(Role, ItemIds, Package, Type);
        _ ->
            ?ERR("错误的背包数据~w", [Type]),
            {ok, Role}
    end.


items_change_bind(Role, ItemIds, Package, PackageType) ->
    {NewItems, NewPackage} = items_change_bind2(ItemIds, Package, []),
    %% 通知客户端
    push_item_info(update, Role, [{PackageType, NewItems}]),
    %% 更新玩家
    NewRole = update_role_package(PackageType, NewPackage, Role),
    {ok, NewRole}.

items_change_bind2([], Pack, ChangeItems) ->
    {ChangeItems, Pack};
items_change_bind2([ItemId | ItemList], Pack = #package{items = Items}, ChangeItems) ->
    case find(by_id, ItemId, Pack) of
        {ok, OldItem} ->
            %% 改为绑定
            NewItem = OldItem#item{bind = 1},
            NewItems = lists:keyreplace(OldItem#item.id, #item.id, Items, NewItem),
            items_change_bind2(ItemList, Pack#package{items = NewItems}, [NewItem | ChangeItems]);
        false ->
            items_change_bind2(ItemList, Pack, ChangeItems)
    end.

%%自动整理
ato_sort(Role) ->
    case sort(bag, Role) of
        {ok, NewBag} ->
            Role#role{p_bag = NewBag};
        {false, Reason} ->
            {false, Reason}
    end.


%% @doc 计算合并道具
merge_item(Item = #item{base_id = Baseid, bind = Bind}, ItemList, MaxNum, BackItems) ->
    %% 获取未满的堆数量
    NoItemList = [I || I = #item{quantity = Q, base_id = Id, bind = B} <- ItemList, Q < MaxNum, Id == Baseid, B == Bind],
    case NoItemList == [] of
        true -> false;
        _ ->
            do_merge_item(NoItemList, Item, MaxNum, ItemList, BackItems)
    end.

%% @doc 实际合并道具
do_merge_item([], Item = #item{id = Id}, _MaxNum, ItemList, BackItems = #{add := AddList}) ->
    NewAddList = lists:keystore(Id, #item.id, AddList, Item),
    {ok, [Item | ItemList], BackItems#{add => NewAddList}};
do_merge_item([OldItem = #item{id = Id, quantity = OldN} | T], Item = #item{quantity = N}, MaxNum, ItemList, BackItems = #{update := UpDataList}) ->
    case OldN + N > MaxNum of
        true ->
            NewItem = OldItem#item{quantity = MaxNum},
            NewItemList = lists:keystore(Id, #item.id, ItemList, NewItem),
            Item1 = Item#item{quantity = OldN + N - MaxNum},
            NewUpDataList = lists:keystore(Id, #item.id, UpDataList, Item1),
            do_merge_item(T, Item1, MaxNum, NewItemList, BackItems#{update => NewUpDataList});
        _ ->
            NewItem = OldItem#item{quantity = OldN + N},
            NewItemList = lists:keystore(Id, #item.id, ItemList, NewItem),
            NewUpDataList = lists:keystore(Id, #item.id, UpDataList, NewItem),
            {ok, NewItemList, BackItems#{update => NewUpDataList}}
    end.



















